//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


package ants.p2p;

import java.util.*;
import java.net.*;
import java.io.*;

public class RoutingTableElement{
  long lastTimeUsed = System.currentTimeMillis();
  public ArrayList routes = new ArrayList();
  String ip = null;
  boolean isTraced = false;
  long lastSeenOn = 0;
  boolean firewalled = false;

  public void setLastTimeUsed(){
    lastTimeUsed = System.currentTimeMillis();
  }

  public long getLastTimeUsed(){
    return this.lastTimeUsed;
  }

  public boolean isTraced(){
    return this.isTraced;
  }

  public void setIP(String ip){
    if(ip == null || ip.equals("")) return;
    if(ip.startsWith("/")) ip = ip.substring(1);
    if(this.ip != null && this.ip.equals(ip)) return;
    String[] parts = ip.split("[:]");
    try {
      InetAddress address = InetAddress.getByName(parts[0]);
      if (!this.isInternetPublicAddress(address)) return;
      new Socket(parts[0], Integer.parseInt(parts[1]));
    }
    catch (NumberFormatException ex1) {
      return;
    }
    catch (UnknownHostException ex1) {
      return;
    }
    catch (IOException ex1) {
      firewalled = true;
    }
    this.ip = ip;
    return;
  }

  public String getIP(){
    return firewalled ? null : this.ip;
  }

  public boolean addTracedRoute(String route){
    if(!this.isTraced()){
      this.routes = new ArrayList();
      this.isTraced = true;
      this.lastSeenOn = Long.MAX_VALUE;
    }
    if(!this.routes.contains(route) ){
      this.routes.add(route);
      return true;
    }else
      return false;
  }

  public boolean addHintRoute(String route, long lastSeenOn){
    if(this.isTraced() == false && this.lastSeenOn < lastSeenOn){
      this.routes = new ArrayList();
      this.lastSeenOn = lastSeenOn;
      this.routes.add(route);
      return true;
    }else
      return false;
  }

  public boolean removeRoute(String route){
    if(this.routes.remove(route)){
      if (this.routes.size() == 0){
        this.isTraced = false;
        this.lastSeenOn = 0;
      }
      return true;
    }else
      return false;
  }

  public List getRoutes(){
    return Collections.unmodifiableList(this.routes);
  }

  public static boolean isInternetPublicAddress(InetAddress address) {
    try {
      byte head = address.getAddress()[0];
      byte body = address.getAddress()[1];
      byte tail = address.getAddress()[2];
      if (head >= 89 && head <= 127)
        return false;
      if (head >= 173 && head <= 187)
        return false;
      if (head >= 224 && head <= 239)
        return false;
      if (head >= 240 && head <= 255)
        return false;
      switch (head) {
        case (byte) 0:
          break;
        case (byte) 1:
          break;
        case (byte) 2:
          break;
        case (byte) 5:
          break;
        case (byte) 10:
          break;
        case (byte) 23:
          break;
        case (byte) 27:
          break;
        case (byte) 31:
          break;
        case (byte) 36:
          break;
        case (byte) 37:
          break;
        case (byte) 39:
          break;
        case (byte) 41:
          break;
        case (byte) 42:
          break;
        case (byte) 46:
          break;
        case (byte) 49:
          break;
        case (byte) 50:
          break;
        case (byte) 58:
          break;
        case (byte) 59:
          break;
        case (byte) 60:
          break;
        case (byte) 71:
          break;
        case (byte) 72:
          break;
        case (byte) 73:
          break;
        case (byte) 74:
          break;
        case (byte) 75:
          break;
        case (byte) 76:
          break;
        case (byte) 77:
          break;
        case (byte) 78:
          break;
        case (byte) 79:
          break;
        case (byte) 128:
          if (body == (byte) 0)
            break;
        case (byte) 169:
          if (body == (byte) 254)
            break;
        case (byte) 172:
          if (body >= (byte) 16 && body <= (byte) 31)
            break;
        case (byte) 189:
          break;
        case (byte) 190:
          break;
        case (byte) 191:
          if (body == (byte) 255)
            break;
        case (byte) 192:
          if (body == (byte) 0 ||
              (body == (byte) 68 && tail == (byte) 185) ||
              body == (byte) 168)
            break;
        case (byte) 197:
          break;
        case (byte) 198:
          if (body >= (byte) 18 && body <= (byte) 19)
            break;
        case (byte) 223:
          break;
        default:
          return true;
      }
      return false;
    }
    catch (Exception e) {
      return false;
    }
  }
}
